package cn.edu.tju.wallet.service;

import cn.edu.tju.core.model.User;
import cn.edu.tju.core.security.repository.UserRepository;
import cn.edu.tju.wallet.domain.VirtualWallet;
import cn.edu.tju.wallet.domain.OverdraftRule;
import cn.edu.tju.wallet.domain.Transaction;
import cn.edu.tju.wallet.domain.Transaction.TransactionType;
import cn.edu.tju.wallet.dto.VipLevelDTO;
import cn.edu.tju.wallet.repository.OverdraftRuleRepository;
import cn.edu.tju.wallet.repository.TransactionRepository;
import cn.edu.tju.wallet.repository.VirtualWalletRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * 支付相关业务服务
 *
 * <p>实现支付、确认收货（解冻）、退款等流程。</p>
 */
@Service
public class PaymentService {

    private final VirtualWalletRepository walletRepository;
    private final TransactionRepository transactionRepository;
    private final UserRepository userRepository;
    private final VipLevelService vipLevelService;
    private final OverdraftRuleRepository overdraftRuleRepository;

    public PaymentService(VirtualWalletRepository walletRepository,
                          TransactionRepository transactionRepository,
                          UserRepository userRepository,
                          VipLevelService vipLevelService,
                          OverdraftRuleRepository overdraftRuleRepository) {
        this.walletRepository = walletRepository;
        this.transactionRepository = transactionRepository;
        this.userRepository = userRepository;
        this.vipLevelService = vipLevelService;
        this.overdraftRuleRepository = overdraftRuleRepository;
    }

    /**
     * 支付功能（保证原子性）
     *
     * @param payerUserId    付款方用户ID
     * @param receiverUserId 收款方用户ID
     * @param amount         支付金额
     * @param orderId        关联订单ID
     * @param allowOverdraft 是否允许使用透支
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void payment(Long payerUserId, Long receiverUserId, BigDecimal amount, Long orderId, boolean allowOverdraft) {
        validatePaymentParams(payerUserId, receiverUserId, amount, orderId);

        Long firstId = Math.min(payerUserId, receiverUserId);
        Long secondId = Math.max(payerUserId, receiverUserId);

        VirtualWallet firstWallet = walletRepository.findByUserIdWithLock(firstId)
                .orElseThrow(() -> new IllegalStateException("钱包不存在: " + firstId));
        VirtualWallet secondWallet = walletRepository.findByUserIdWithLock(secondId)
                .orElseThrow(() -> new IllegalStateException("钱包不存在: " + secondId));

        VirtualWallet payer = Objects.equals(payerUserId, firstId) ? firstWallet : secondWallet;
        VirtualWallet receiver = Objects.equals(payerUserId, firstId) ? secondWallet : firstWallet;

        BigDecimal payerBalanceBefore = payer.getBalance();
        BigDecimal receiverBalanceBefore = receiver.getBalance();

        // 如果允许透支且余额不足，需要先初始化透支额度
        if (allowOverdraft && payer.getAvailableBalance().compareTo(amount) < 0) {
            initializeOverdraftLimit(payer);
            // 重新保存钱包以更新透支额度
            walletRepository.save(payer);
        }

        payer.transfer(receiver, amount, allowOverdraft);

        walletRepository.save(payer);
        walletRepository.save(receiver);

        Transaction payerTx = new Transaction(
                payer.getId(),
                TransactionType.PAYMENT,
                amount.negate(),
                payerBalanceBefore,
                payer.getBalance()
        );
        payerTx.setOrderId(orderId);
        payerTx.setRemark("支付订单: " + orderId + (allowOverdraft ? " (允许透支)" : ""));
        payerTx = transactionRepository.save(payerTx);

        Transaction receiverTx = new Transaction(
                receiver.getId(),
                TransactionType.RECEIPT,
                amount,
                receiverBalanceBefore,
                receiver.getBalance()
        );
        receiverTx.setOrderId(orderId);
        receiverTx.setRemark("收款订单: " + orderId + " (冻结)");
        receiverTx.setRelatedTransactionId(payerTx.getId());
        receiverTx = transactionRepository.save(receiverTx);

        payerTx.setRelatedTransactionId(receiverTx.getId());
        transactionRepository.save(payerTx);

        // VIP升级检查：支付方消费增加
        updateUserVipLevelAfterPayment(payerUserId, amount);
    }

    /**
     * 支付功能（保证原子性）- 兼容旧版本，默认不允许透支
     *
     * @param payerUserId    付款方用户ID
     * @param receiverUserId 收款方用户ID
     * @param amount         支付金额
     * @param orderId        关联订单ID
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void payment(Long payerUserId, Long receiverUserId, BigDecimal amount, Long orderId) {
        payment(payerUserId, receiverUserId, amount, orderId, false);
    }

    /**
     * 支付成功后更新用户VIP等级
     * @param userId 用户ID
     * @param amount 支付金额（消费金额）
     */
    private void updateUserVipLevelAfterPayment(Long userId, BigDecimal amount) {
        try {
            // 重新从数据库查询最新用户数据
            User user = userRepository.findById(userId).orElse(null);
            if (user == null) return;

            // 增加累计消费金额
            user.addConsumption(amount);

            // 保存用户信息（包含新增的消费金额）
            user = userRepository.save(user);

            // 检查VIP升级
            VipLevelDTO newLevel = vipLevelService.upgradeUserVipLevel(user);

            // 保存升级后的用户信息
            user = userRepository.save(user);

            if (newLevel != null) {
                System.out.println(String.format(
                    "用户 %s 支付后VIP升级成功: %s (等级%d)",
                    user.getUsername(), newLevel.getName(), newLevel.getLevel()
                ));
            }
        } catch (Exception e) {
            // 记录日志但不中断支付流程
            System.err.println("VIP升级失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 确认收货（解冻）
     *
     * @param orderId 订单ID
     */
    @Transactional
    public void confirmReceipt(Long orderId) {
        if (orderId == null) {
            throw new IllegalArgumentException("订单ID不能为空");
        }

        List<Transaction> transactions = transactionRepository.findByOrderId(orderId);
        if (transactions.isEmpty()) {
            throw new IllegalStateException("未找到订单相关交易: " + orderId);
        }

        Transaction receiptTx = transactions.stream()
                .filter(tx -> tx.getType() == TransactionType.RECEIPT)
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("收款记录不存在: " + orderId));

        VirtualWallet receiver = walletRepository.findByIdWithLock(receiptTx.getWalletId())
                .orElseThrow(() -> new IllegalStateException("钱包不存在: " + receiptTx.getWalletId()));

        BigDecimal amount = receiptTx.getAmount();
        BigDecimal balanceBefore = receiver.getBalance();

        receiver.unfreeze(amount);

        walletRepository.save(receiver);

        Transaction unfreezeTx = new Transaction(
                receiver.getId(),
                TransactionType.UNFREEZE,
                amount,
                balanceBefore,
                receiver.getBalance()
        );
        unfreezeTx.setOrderId(orderId);
        unfreezeTx.setRemark("解冻: 确认收货 " + orderId);
        unfreezeTx.setRelatedTransactionId(receiptTx.getId());
        transactionRepository.save(unfreezeTx);

        // VIP升级检查：收款方充值增加（收到的款项算作充值）
        // 需要从wallet获取userId
        Long receiverUserId = receiver.getUserId();
        updateUserVipLevelAfterRecharge(receiverUserId, amount);
    }

    /**
     * 充值成功后更新用户VIP等级
     * @param userId 用户ID
     * @param amount 充值金额
     */
    private void updateUserVipLevelAfterRecharge(Long userId, BigDecimal amount) {
        try {
            // 重新从数据库查询最新用户数据
            User user = userRepository.findById(userId).orElse(null);
            if (user == null) return;

            // 增加累计充值金额
            user.addRecharge(amount);

            // 保存用户信息（包含新增的充值金额）
            user = userRepository.save(user);

            // 检查VIP升级
            VipLevelDTO newLevel = vipLevelService.upgradeUserVipLevel(user);

            // 保存升级后的用户信息
            user = userRepository.save(user);

            if (newLevel != null) {
                System.out.println(String.format(
                    "用户 %s 收款后VIP升级成功: %s (等级%d)",
                    user.getUsername(), newLevel.getName(), newLevel.getLevel()
                ));
            }
        } catch (Exception e) {
            // 记录日志但不中断流程
            System.err.println("VIP升级失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 退款
     *
     * @param orderId 订单ID
     */
    @Transactional
    public void refund(Long orderId) {
        if (orderId == null) {
            throw new IllegalArgumentException("订单ID不能为空");
        }

        List<Transaction> transactions = transactionRepository.findByOrderId(orderId);
        if (transactions.isEmpty()) {
            throw new IllegalStateException("未找到订单相关交易: " + orderId);
        }

        Transaction paymentTx = transactions.stream()
                .filter(tx -> tx.getType() == TransactionType.PAYMENT)
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("支付记录不存在: " + orderId));

        Transaction receiptTx = transactions.stream()
                .filter(tx -> tx.getType() == TransactionType.RECEIPT)
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("收款记录不存在: " + orderId));

        Long payerWalletId = paymentTx.getWalletId();
        Long receiverWalletId = receiptTx.getWalletId();

        Long firstId = Math.min(payerWalletId, receiverWalletId);
        Long secondId = Math.max(payerWalletId, receiverWalletId);

        VirtualWallet first = walletRepository.findByIdWithLock(firstId)
                .orElseThrow(() -> new IllegalStateException("钱包不存在: " + firstId));
        VirtualWallet second = walletRepository.findByIdWithLock(secondId)
                .orElseThrow(() -> new IllegalStateException("钱包不存在: " + secondId));

        VirtualWallet payer = Objects.equals(payerWalletId, first.getId()) ? first : second;
        VirtualWallet receiver = Objects.equals(payerWalletId, first.getId()) ? second : first;

        BigDecimal refundAmount = receiptTx.getAmount();

        receiver.unfreeze(refundAmount);
        if (receiver.getAvailableBalance().compareTo(refundAmount) < 0) {
            throw new IllegalStateException("收款方可用余额不足以退款");
        }

        BigDecimal receiverBalanceBefore = receiver.getBalance();
        BigDecimal payerBalanceBefore = payer.getBalance();

        receiver.setAvailableBalance(receiver.getAvailableBalance().subtract(refundAmount));
        receiver.setBalance(receiver.getBalance().subtract(refundAmount));

        payer.setAvailableBalance(payer.getAvailableBalance().add(refundAmount));
        payer.setBalance(payer.getBalance().add(refundAmount));

        walletRepository.save(payer);
        walletRepository.save(receiver);

        Transaction payerRefundTx = new Transaction(
                payer.getId(),
                TransactionType.REFUND,
                refundAmount,
                payerBalanceBefore,
                payer.getBalance()
        );
        payerRefundTx.setOrderId(orderId);
        payerRefundTx.setRemark("退款入账: " + orderId);
        payerRefundTx = transactionRepository.save(payerRefundTx);

        Transaction receiverRefundTx = new Transaction(
                receiver.getId(),
                TransactionType.REFUND,
                refundAmount.negate(),
                receiverBalanceBefore,
                receiver.getBalance()
        );
        receiverRefundTx.setOrderId(orderId);
        receiverRefundTx.setRemark("退款出账: " + orderId);
        receiverRefundTx.setRelatedTransactionId(payerRefundTx.getId());
        receiverRefundTx = transactionRepository.save(receiverRefundTx);

        payerRefundTx.setRelatedTransactionId(receiverRefundTx.getId());
        transactionRepository.save(payerRefundTx);
    }

    private void validatePaymentParams(Long payerUserId, Long receiverUserId,
                                       BigDecimal amount, Long orderId) {
        if (payerUserId == null || receiverUserId == null) {
            throw new IllegalArgumentException("用户ID不能为空");
        }
        if (Objects.equals(payerUserId, receiverUserId)) {
            throw new IllegalArgumentException("付款方与收款方不能相同");
        }
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("支付金额必须大于0");
        }
        if (orderId == null) {
            throw new IllegalArgumentException("订单ID不能为空");
        }
    }

    /**
     * 为钱包初始化透支额度（根据VIP等级和透支规则）
     * @param wallet 钱包
     */
    private void initializeOverdraftLimit(VirtualWallet wallet) {
        if (wallet.getOverdraftLimit().compareTo(BigDecimal.ZERO) > 0) {
            // 已有透支额度，不需要重新初始化
            return;
        }

        try {
            // 获取用户VIP信息（优先从User表获取真实等级）
            User user = userRepository.findById(wallet.getUserId()).orElse(null);
            Integer userVipLevel = 0;

            if (user != null && user.getVipLevelValue() != null) {
                userVipLevel = user.getVipLevelValue();
                // 同步到钱包记录
                wallet.setVipLevel(userVipLevel);
            } else {
                // 如果User表中没有，使用钱包表的vipLevel
                userVipLevel = wallet.getVipLevel();
            }

            // 查询适用的透支规则
            OverdraftRule rule = overdraftRuleRepository
                    .findFirstByStatusAndMinVipLevelLessThanEqualOrderByMinVipLevelDesc(
                            OverdraftRule.RuleStatus.ACTIVE, userVipLevel)
                    .orElse(null);

            if (rule == null) {
                // 没有适用的透支规则，保持额度为0
                System.out.println("未找到适用的透支规则，VIP等级: " + userVipLevel);
                return;
            }

            // 计算VIP倍数
            BigDecimal overdraftMultiplier = BigDecimal.ONE;
            if (userVipLevel > 0) {
                var vipLevelOpt = vipLevelService.getVipLevelByLevel(userVipLevel);
                if (vipLevelOpt.isPresent()) {
                    var vipLevelDTO = vipLevelOpt.get();
                    if (vipLevelDTO.getOverdraftMultiplier() != null) {
                        overdraftMultiplier = vipLevelDTO.getOverdraftMultiplier();
                    }
                }
            }

            // 计算并设置透支额度
            BigDecimal baseOverdraftLimit = rule.getOverdraftLimit();
            BigDecimal vipOverdraftLimit = baseOverdraftLimit.multiply(overdraftMultiplier);
            wallet.setOverdraftLimit(vipOverdraftLimit);

            System.out.println(String.format(
                "初始化透支额度成功 - 用户ID: %d, VIP等级: %d, 基础额度: %s, 倍数: %s, 最终额度: %s",
                wallet.getUserId(), userVipLevel, baseOverdraftLimit, overdraftMultiplier, vipOverdraftLimit
            ));

        } catch (Exception e) {
            // 初始化失败，保持额度为0，不影响支付流程
            System.err.println("初始化透支额度失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

